﻿using CSRedis;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using WH.Common.Enums;
using WH.Common.Config;
using WH.Common.Config.Options;
using Rw.Core.Redis;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection.Extensions;
using WH.Common.Cache;
using System;
using System.IO;
using System.Threading.Tasks;
using System.Collections.Generic;
using Rw.Core.Common.Helper;

namespace WH.Extensions.Setup
{
    public static class CachingSetup
    {
        /// <summary>
        /// 注入缓存模块
        /// </summary>
        /// <param name="services"></param>
        /// <param name="cacheMode">1:Memory 2:Redis</param>
        /// <exception cref="ArgumentNullException"></exception>
        public static void AddCacheSetup(this IServiceCollection services)
        {
            IConfigurationCenter config = services.BuildServiceProvider().GetRequiredService<IConfigurationCenter>();

            IConfiguration configuration = services.BuildServiceProvider().GetRequiredService<IConfiguration>();


            services.Configure<CacheOpttions>(configuration.GetSection("CacheOpttions"));
            var cacheOptionsMonitor = services.BuildServiceProvider().GetRequiredService<IOptionsMonitor<CacheOpttions>>();

            services.Configure<RedisOptions>(configuration.GetSection("RedisOptions"));
            var optionsMonitor = services.BuildServiceProvider().GetRequiredService<IOptionsMonitor<RedisOptions>>();

            cacheOptionsMonitor.OnChange((options) =>
            {
                SetCacheSetup(services, cacheOptionsMonitor.CurrentValue, optionsMonitor.CurrentValue);
            });

            optionsMonitor.OnChange((options) =>
            {
                SetCacheSetup(services, cacheOptionsMonitor.CurrentValue, optionsMonitor.CurrentValue);
            });

            SetCacheSetup(services, cacheOptionsMonitor.CurrentValue, optionsMonitor.CurrentValue);
        }


        private static void SetCacheSetup(IServiceCollection services, CacheOpttions cacheOptions, RedisOptions redisOptions)
        {

            bool enable = cacheOptions.Enable;
            CacheModeEnum cacheMode = cacheOptions.Mode;

            if (services == null)
            {
                throw new ArgumentNullException(nameof(services));
            }

            //services.AddMemoryCache();
            services.AddSingleton<IMemoryCache>(factory =>
            {
                return memoryCache;
            });

            var reove = services.RemoveAll<ICaching>;

            reove();
            services.AddSingleton<ICaching, MemoryCaching>();


            if (enable)
            {
                if (cacheMode == CacheModeEnum.Redis)
                {
                    if (redisOptions == null)
                    {
                        throw new ArgumentException("请检查RedisOptions配置是否添加");
                    }

                    var redis = new CSRedisClient($"{redisOptions.Default.Server}:{redisOptions.Default.Port},password={redisOptions.Default.Password},defaultDatabase={redisOptions.Default.DefaultDatabase}");


                    if (redis.Ping())
                    {
                        services.AddSingleton(redis);

                        //services.AddSingleton<IRedisService, RedisService>();

                        reove();
                        services.AddSingleton<ICaching, RedisCaching>();

                    }
                }
            }
            var caches = services.BuildServiceProvider().GetRequiredService<ICaching>();
        }

        private static readonly object _Object = new object();
        private static IMemoryCache _cacheInstace = null!;

        private static IMemoryCache memoryCache
        {
            get
            {
                if (_cacheInstace == null)
                {
                    lock (_Object)
                    {
                        if (_cacheInstace == null)
                        {
                            _cacheInstace = new MemoryCache(new MemoryCacheOptions());
                        }
                    }
                }
                return _cacheInstace;
            }
        }
    }
}
